package com.baomidou.mybatisplus.samples.quickstart.service;

import com.baomidou.mybatisplus.samples.quickstart.entity.Goods;
import com.baomidou.mybatisplus.samples.quickstart.entity.Order;
import com.baomidou.mybatisplus.samples.quickstart.mapper.GoodsDao;
import com.baomidou.mybatisplus.samples.quickstart.mapper.OrderDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author zhang
 */
@Service
@Slf4j
public class GoodsService {

    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private OrderDao orderDao;

    /**
     * 扣减库存
     * @param gid 商品id
     * @param uid 用户id
     * @return SUCCESS 1 FAILURE 0
     */
    public int sellGoods(int gid, int uid) {
        int retryCount = 0;
        int update = 0;
        // 获取库存
        Goods goods = goodsDao.getStock(gid);
        if (goods.getStock() > 0) {
            // 乐观锁更新库存
            // 更新失败，说明其他线程已经修改过数据，本次扣减库存失败，可以重试一定次数或者返回
            // 最多重试3次
            while(retryCount < 3 && update == 0){
                update = this.reduceStock(gid);
                retryCount++;
            }
            if(update == 0){
                log.error("库存不足");
                return 0;
            }
            // 库存扣减成功，生成订单
            Order order = new Order();
            order.setUid(uid);
            order.setGid(gid);
            int result = orderDao.insertOrder(order);
            return result;
        }
        // 失败返回
        return 0;
    }


    /**
     * 减库存
     *
     * 由于默认的事务隔离级别是可重复读，会导致在同一个事务中查询3次goodsDao.getStock()
     * 得到的数据始终是相同的，所以需要提取reduceStock方法。每次循环都启动新的事务尝试扣减库存操作。
     */
    @Transactional(rollbackFor = Exception.class)
    public  int  reduceStock(int gid){
        int result = 0;
        //1、查询商品库存
        Goods goods = goodsDao.getStock(gid);
        //2、判断库存是否充足
        if(goods.getStock() >= 0){
            //3、减库存
            // 乐观锁更新库存
            result = goodsDao.decreaseStockForVersion(gid, goods.getVersion());
        }
        return result;
    }
}